<template>
  <div
    v-ripple
    class="menu-item v-radius v-flex"
    :class="{ 'active-name': active }"
    :style="styles"
    @click="onClickMenuItem"
    @mouseenter="onMouseEnterMenuItem"
    @mouseleave="onMouseLeaveMenuItem"
  >
    <p class="menu-item-block v-flex">
      <v-icon :icon="item.icon" :styles="{ marginRight: '10px' }" />
      <span v-if="expand" class="v-menu-text">{{ item.title }}</span>
      <v-icon v-if="hasChild && expand" class="flag-icon" :icon="flagIcon"></v-icon>
    </p>
    <div class="menu-move v-radius" :class="{ 'active-menu-move': active }"></div>
    <!-- 悬浮框 -->
    <transition name="menu-pos">
      <div v-if="showMenuPos" class="v-menu-pos-wrapper">
        <div class="v-menu-pos-inner">
          <!-- <div class="diamond-arrow v-shadow"></div> -->
          <menu-item-pos
            v-for="child of item.children"
            :child="child"
            :active-name-item-pos="activeNameItemPos"
            @clickMenuItemPos="(childName) => onClickMenuItemPos(item.name, childName)"
          />
        </div>
      </div>
    </transition>
  </div>
  <div v-if="hasChild" class="item-list v-radius">
    <menu-item
      v-for="child of item.children"
      :ref="receiveChildren"
      :item="child"
      :parent="item"
      :expand="expand"
      :unique-opened="uniqueOpened"
      :active-name="activeName"
      :old-active-name="oldActiveName"
      :init-name="initName"
      :bg="bg"
      :second-bg="secondBg"
      :styles="styles"
      :txt-color="txtColor"
      @clickMenuItem="$emit('clickMenuItem', child.name)"
      @closeMenuList="$emit('closeMenuList', child.name)"
      @changeActiveName="$emit('changeActiveName', item.name)"
      @changeMenuItemPos="$emit('changeMenuItemPos', activeName)"
      @setExpand="$emit('setExpand', item.name, true)"
    ></menu-item>
  </div>
</template>

<script lang='ts'>
import { defineComponent, PropType, computed, ref, watch, nextTick, inject } from 'vue';
import { useRouter } from 'vue-router';
import VIcon from '@/components/Icon.vue';
import MenuItemPos from '@/components/navigation/MenuItemPos.vue';
import { INavigationItem } from '@/interface';

export default defineComponent({
  name: "MenuItem",
  components: {
    VIcon,
    MenuItemPos
  },
  props: {
    uniqueOpened: Boolean,
    expand: Boolean,
    activeName: String,
    activeNameItemPos: String,
    oldActiveName: String,
    initName: String,
    bg: String,
    secondBg: String,
    txtColor: String,
    item: {
      type: Object as PropType<INavigationItem>,
      default: () => ({})
    },
    parent: {
      type: Object as PropType<INavigationItem>,
      default: () => ({})
    },
    styles: {
      type: Object,
      default: () => ({})
    }
  },
  emits: ['closeMenuList', 'clickMenuItem', 'clickMenuItemPos', 'changeActiveName', 'changeMenuItemPos', 'setExpand'],
  setup(props, ctx) {
    const router = useRouter();
    const ARROWS_BOTTOM = 'icon-xiajiantou';
    const ARROWS_TOP = 'icon-shangjiantou';
    const g_bg = inject("$bg");
    // true代表开启状态, false代表未开启
    const isExpand = ref(false);
    const flagIcon = ref(ARROWS_BOTTOM);
    const hasChild = computed(() => props.item.children && props.item.children.length > 0);
    const listHeight = ref('0px');
    const children = ref<Array<any>>([]);
    const showMenuPos = ref(false);
    const itemListHeight = ref(`${props.item.children?.length * 40}px`);
    const menuPosLeft = ref('0px');
    const menuPosTop = ref('0px');
    const menuPosHeight = computed(() => `${(parseInt(itemListHeight.value) + 16)}px`);
    /* 监听外围是否展开 */
    watch(() => props.expand, (v) => {
      
      if (!v && props.activeName === props.item.name) {
        ctx.emit('changeMenuItemPos', props.activeName);
        ctx.emit('changeActiveName', props.parent.name);
      }
      if (v) {
        if (props.activeName === props.item.name && props.item.children.length > 0) {
          // 1.展开父级
          ctx.emit('setExpand', props.item.name, true);
          // 2.选中子级
          ctx.emit('changeActiveName', props.activeNameItemPos);
        }
      }
    });
    /* 监听是否初始化 */
    watch(() => props.initName, (v) => {
      if (props.item.name === v) {
        // 1.没有父节点, 代表当前的菜单是一级菜单, 直接跳转
        if (props.parent.name === 'null') {
          onClickMenuItem();
        } 
        // 2.有父节点, 先展开父节点, 再点击当前节点
        else {
          // 1.展开
          ctx.emit('setExpand', props.parent.name, true);
          // 2.点击自己
          onClickMenuItem();
        }
      }
    });
    /* 监听自己是否展开 */
    watch(isExpand, (v) => {
      listHeight.value = v ? itemListHeight.value : '0px';
      flagIcon.value = v ? ARROWS_TOP : ARROWS_BOTTOM;
    });
    const active = computed(() => props.activeName === props.item.name);
    /* 点击菜单 */
    const onClickMenuItem = () => {
      // 如果没有子节点, 直接跳转
      if (!hasChild.value) {
        ctx.emit('clickMenuItem', props.item.name);
        router.push({ name: props.item.name });
        return;
      }
      // 如果点击的时候是收缩状态, 且当前点击的是一个嵌套导航则直接返回
      if (!props.expand) return;
      // 1.变换图标
      flagIcon.value = flagIcon.value === ARROWS_BOTTOM ? ARROWS_TOP : ARROWS_BOTTOM;
      // 2.计算list的height
      listHeight.value = isExpand.value ? '0px' : itemListHeight.value;
      // 3.如果isExpand为false, 也就是下一次要展开的时候判断一下是否只允许一个节点开启
      if (!isExpand.value && props.uniqueOpened) {
        ctx.emit('closeMenuList', props.item.name);
      }
      // 变换开启状态
      isExpand.value = !isExpand.value;
    };
    // 关闭自身的list
    const closeMenuList = (name: string) => (props.item.name !== name) && (isExpand.value = false);
    // 接收子节点
    const receiveChildren = (component: any) => children.value.push(component);
    // 鼠标进入
    const onMouseEnterMenuItem = (event: MouseEvent) => {
      if (!props.expand && props.item.children && props.item.children.length > 0) {
        const { top, width, left } = (event.target as HTMLElement).getBoundingClientRect();
        menuPosLeft.value = `${left + width}px`;
        menuPosTop.value = `${top - 7}px`;
        showMenuPos.value = true;
      }
    };
    // 鼠标离开
    const onMouseLeaveMenuItem = (event: MouseEvent) => nextTick(() => showMenuPos.value = false);
    // 点击定位菜单
    const onClickMenuItemPos = (parentName: string | undefined, childName: string) => {
      // 发送父级的name
      ctx.emit('clickMenuItem', parentName);
      // 发送实际的name
      ctx.emit('clickMenuItemPos', childName);
    }
    // 设置展开状态
    const setExpand = (state: boolean) => {
      if (props.uniqueOpened) {
        ctx.emit('closeMenuList', props.item.name);
      }
      isExpand.value = state;
    };
    return {
      isExpand,
      g_bg,
      active,
      hasChild,
      flagIcon,
      children,
      showMenuPos,
      listHeight,
      menuPosTop,
      menuPosLeft,
      itemListHeight,
      menuPosHeight,
      ARROWS_TOP, 
      ARROWS_BOTTOM,
      setExpand,
      closeMenuList,
      onClickMenuItem,
      receiveChildren,
      onMouseEnterMenuItem,
      onMouseLeaveMenuItem,
      onClickMenuItemPos
    };
  }
})
</script>

<style scoped lang="scss">
  @import '@/styles/main.scss';
  .menu-pos-enter-active {
  transition: all 0.3s ease-out;
}

.menu-pos-leave-active {
  transition: all 0.3s cubic-bezier(1, 0.5, 0.8, 1);
}

.menu-pos-enter-from,
.menu-pos-leave-to {
  transform: translateX(20px);
  opacity: 0;
}

.flag-icon {
  position: absolute;
  right: 20px;
}
.v-menu-text {
  overflow: hidden;
}
.v-menu-pos-wrapper {
  width: 200px;
  position: fixed;
  z-index: 2;
  padding: 8px;
  height: v-bind(menuPosHeight);
  left: v-bind(menuPosLeft);
  top: v-bind(menuPosTop);
  transition: all .25s ease-out;
}

.v-menu-pos-inner {
  width: 90%;
  background-color: v-bind(g_bg);
  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.12), 0 0 6px rgba(0, 0, 0, 0.04);
  border-radius: 10px;
  margin-left: 8px;
  padding: 8px;
}
.diamond-arrow {
  width: 15px;
  height: 15px;
  background-color: v-bind(g_bg);
  position: absolute;
  left: 18px;
  top: 14px;
  transform-origin: center;
  transform: rotateZ(50deg);
  border-radius: 2px;
}
.v-navigation {
  height: 100%;
  background-color: v-bind(bg);
}

.icon-small {
  width: 0.8em;
  height: 0.8em;
}

.menu-item {
  width: 100%;
  position: relative;
  color: v-bind(txtColor);
  cursor: pointer;
  overflow: hidden;
  transition: all 0.25s ease;
  background-color: v-bind(bg);
  line-height: 40px;
  height: 40px;
  overflow: hidden;
  align-items: center;
}
.menu-item:hover > .menu-move {
  opacity: 0.2;
}

.active-menu-move {
  opacity: 0.2 !important;
}

.active-name {
  /*color: #409EFF;*/
  color: $primary-color;
}

.menu-move {
  width: 100%;
  height: 40px;
  opacity: 0;
  background-color: currentColor;
  transition: all 0.25s ease;
  position: absolute;
  left: 50%;
  top: 0;
  transform: translateX(-50%);
}

.item-list {
  width: 100%;
  height: v-bind(listHeight);
  overflow: hidden;
  transition: all 0.25s ease-out;
  font-size: inherit;
  background-color: v-bind(secondBg);
}

.item-list > .menu-item {
  font-size: inherit;
  background-color: v-bind(secondBg);
}

.menu-item > .menu-item-block {
  padding: 0 20px;
  font-size: inherit;
  align-items: center;
}
.show {
  height: auto !important;
  max-height: 9999px !important;
}
</style>